#pragma once
#include <Preprocessor.h>
#include <glm/glm.hpp>
#include <memory>
#include <string>
#include <unordered_map>
namespace Umikaze::Core {

class Texture;
class Buffer;
class Uniform;
class Attribute;
class UniformBlock;
class InternalShader;

// class Texture {
// public:
//   int32_t _textureId;
// };
class Shader {

  CORE_OBJECT

public:
  Shader(const std::string &vertPath, const std::string &fragPath,
         const std::string &geomPath = std::string());

  void setBool(const std::string &name, bool value);
  // ------------------------------------------------------------------------
  void setInt(const std::string &name, int value);
  // ------------------------------------------------------------------------
  void setFloat(const std::string &name, float value);

  // ------------------------------------------------------------------------
  void setVec2(const std::string &name, const glm::vec2 &value);
  void setVec2(const std::string &name, float x, float y);
  // ------------------------------------------------------------------------
  void setVec3(const std::string &name, const glm::vec3 &value);
  void setVec3(const std::string &name, float x, float y, float z);
  // ------------------------------------------------------------------------
  void setVec4(const std::string &name, const glm::vec4 &value);
  void setVec4(const std::string &name, float x, float y, float z, float w);
  // ------------------------------------------------------------------------
  //   void setMat2(const std::string &name, const glm::mat2 &mat) const;
  //   //
  // ------------------------------------------------------------------------
  //   void setMat3(const std::string &name, const glm::mat3 &mat) const;
  // ------------------------------------------------------------------------
  void setMat4(const std::string &name, const glm::mat4 &mat);

  void setBuffer(const std::string &name,
                 const std::shared_ptr<Buffer> &buffer);

  void setFloatArray(const std::string &name, const std::vector<float> &number);

  // TODO: 强耦合了，是否需要解决一下？
  void setTexture(const std::string &name,
                  const std::shared_ptr<Texture> &texture);

  //这个函数应该在shader bind之前调用，其他的函数反之
  void setCondition(const std::string &name, bool state);

  ~Shader();

private:
  void bind();

private:
  std::unique_ptr<InternalShader> _internalShader;
  uint32_t _version = 0;

private:
  std::unordered_map<std::string, bool> _bools;
  std::unordered_map<std::string, int> _ints;
  std::unordered_map<std::string, float> _floats;

  // TODO: 改成指针以节省内存
  std::unordered_map<std::string, glm::vec2> _vec2s;
  std::unordered_map<std::string, glm::vec3> _vec3s;
  std::unordered_map<std::string, glm::vec4> _vec4s;
  std::unordered_map<std::string, glm::mat4> _mat4s;

  std::unordered_map<std::string, std::weak_ptr<Texture>> _textures;
  std::unordered_map<std::string, std::weak_ptr<Buffer>> _blocks;
};
} // namespace Umikaze::Core